#!/usr/bin/env python
#
# Copyright 2008 Google Inc.
# Copyright 2010 Joe LaPenna
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
#     http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
#

"""Google Places client."""

import sys
import hashlib
import urllib
import hmac
import base64
import urlparse

from google.appengine.api import urlfetch


def sign_url(url, private_key):
  """Sign a url and return the signed result."""
  url = urlparse.urlparse(url)

  # We only need to sign the path+query part of the string
  url_to_sign = url.path + "?" + url.query

  # Decode the private key into its binary format
  decoded_key = base64.urlsafe_b64decode(private_key)

  # Create a signature using the private key and the URL-encoded
  # string using HMAC SHA1. This signature will be binary.
  signature = hmac.new(decoded_key, url_to_sign, hashlib.sha1)

  # Encode the binary signature into base64 for use within a URL
  encoded_signature = base64.urlsafe_b64encode(signature.digest())
  original_url = url.scheme + "://" + url.netloc + url.path + "?" + url.query
  return original_url + "&signature=" + encoded_signature


class Places(object):
  """API access to Places."""

  DOMAIN = 'http://maps.google.com'

  SEARCH_PATH = '/maps/api/place/search/json'
  SEARCH_URL = DOMAIN + SEARCH_PATH

  DETAILS_PATH = '/maps/api/place/details/json'
  DETAILS_URL = DOMAIN + DETAILS_PATH

  def __init__(self, client_id, client_key):
    self.client_id = client_id
    self.client_key = client_key

  def placeSearch(self, latitude, longitude, radius, sensor, callback=None):
    """http://code.google.com/apis/maps/documentation/places/#PlaceSearchRequests"""
    parameters = {
      'location': '%s,%s' % (latitude, longitude),
      'radius': radius,
      'sensor': sensor,
      'client': self.client_id,
    }
    query = urllib.urlencode(parameters)
    url = sign_url(Places.SEARCH_URL + '?' + query, self.client_key)
    return self._fetch(url, callback=callback)

  def placeDetails(self, reference, sensor, callback=None):
    """http://code.google.com/apis/maps/documentation/places/#PlaceSearchRequests"""
    parameters = {
      'reference': reference,
      'sensor': sensor,
      'client': self.client_id,
    }
    query = urllib.urlencode(parameters)
    url = sign_url(Places.DETAILS_URL + '?' + query, self.client_key)
    return self._fetch(url, callback=callback)

  def _fetch(self, url, callback=None):
    if callback:
      rpc = urlfetch.create_rpc()
      def wrapped_callback():
        callback(rpc)
      rpc.callback = wrapped_callback
      urlfetch.make_fetch_call(rpc, url=url)
      return rpc
    else:
      return urlfetch.fetch(url)

  def get_places_details(self, places_client, places_list, callback):
    """Get the details of each place in the places list: phone, etc."""
    rpcs = []
    for place in places_list:
      reference = place['reference']
      rpcs.append(
          self.placeDetails(reference, sensor='false', callback=callback))
    for rpc in rpcs:
      rpc.wait()
